package znet

import (
	"fmt"
	"zinx/utils"
	zinterface "zinx/zInterface"
)

/*
	消息处理模块的实现
*/

 type MsgHandle struct{
	//存放每个msgID对应的处理方法的集合
	Apis map[uint32]zinterface.IRouter
	//负责worker取任务的消息队列，一个队列对应一个worker
	TaskQueue []chan zinterface.IRequest
	//业务工作池中worker的数量--应由全局配置
	WorkerPoolSize uint32
	// 是否已经开启了worker工作池--用于防止多次开启工作池
	isOpenedWorkerPool bool
 }

 //MsgHandle的初始化构造函数
 func NewMsgHandle()*MsgHandle{
	return &MsgHandle{
		Apis: make(map[uint32]zinterface.IRouter),
		WorkerPoolSize: utils.GlobalObject.WorkerPoolSize,
		TaskQueue: make([]chan zinterface.IRequest, utils.GlobalObject.WorkerPoolSize),
		isOpenedWorkerPool: false,
	}
 }

 //调度/执行 消息ID对应的handle处理逻辑函数
 func(mh *MsgHandle)DoMsgHandle(request zinterface.IRequest){
	//先获取待执行的router
	handle,ok := mh.Apis[request.GetMsgID()]
	if !ok{
		//如果该消息类型没有注册，直接报错
		panic(fmt.Sprintf("msgID = %d 尚未注册了，无法调用",request.GetMsgID()))
	}
	// 如果有注册，则调用相应的方法
	handle.PreHandle(request)
	handle.Handle(request)
	handle.PostHandle(request)
 }

 //根据消息ID添加对应的handle处理逻辑函数
 func(mh *MsgHandle)AddRouter(msgID uint32,router zinterface.IRouter){
	// 判断当前msg所有绑定的Apis处理方法是否已经存在
	if _,ok := mh.Apis[msgID];ok{
		//id已经存在，这是重复注册了，直接报错
		panic(fmt.Sprintf("msgID = %d 已经注册了，不能重复注册！",msgID))
	}

	// 添加msg和API的对应关系
	mh.Apis[msgID] = router
	fmt.Printf("add api msgID = %d success\n",msgID)
 }

 //开启worker工作池--这个只能开启一次，因为我们的服务器中只有一个工作池
 func(mh *MsgHandle)StartWorkerPool(){
	//防止多次调用StartWorkerPool方法
	if mh.isOpenedWorkerPool{ //如果已经开启了，则不再开启，直接返回
		return
	}
	mh.isOpenedWorkerPool = true
	//根据工作池的数量进行创建
	for i := 0; i < int(mh.WorkerPoolSize); i++ {
		//每个任务队列都是一下channel，需要先开辟空间
		//管道的长度就是每个队列允许的最大任务数量
		mh.TaskQueue[i] = make(chan zinterface.IRequest,utils.GlobalObject.MaxWorkerTaskLen)
		//启动一个goroutine 去承载一个任务
		go mh.startOneWorker(i)
	}
 }

 //开启一个工作池，在这里面阻塞的等待每一个任务的到来
 func(mh *MsgHandle)startOneWorker(workerID int){
	fmt.Printf("workerID = %d is started...\n",workerID)
	// for{
	// 	select{
	// 	case req := <- mh.TaskQueue[workerID]:
	// 		mh.DoMsgHandle(req)
	// 	}
	// }
	for req := range mh.TaskQueue[workerID] {
		mh.DoMsgHandle(req)
	}
 }

 //把消息交给TaskQueue，由worker进行处理
 func(mh *MsgHandle)SendMsgToQueue(req zinterface.IRequest){
	workerID := mh.getWorkerID(req)
	mh.TaskQueue[workerID] <- req
 }

 //根据connID进行平均分配
 func (mh *MsgHandle)getWorkerID(req zinterface.IRequest)int{
	connID := req.GetConnection().GetConnID()
	id := int(connID) % int(mh.WorkerPoolSize)
	fmt.Printf("connID = %d,msgID = %d,work at workerID = %d\n",
		connID,req.GetMsgID(),id)
	return id
 }